package shapes.shapes2D.distribution.poissondisk 
{
	import flash.display.BitmapData;
	import flash.display.Graphics;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	import shapes.shapes2D.Dot;
	import utils.GeomUtils;
	
	/**
	 * 
	 * http://www.devmag.org.za/articles/55-POISSON-DISK-SAMPLING/#top2
	 * 
	 * @author Nicolas Barradeau
	 * http://en.nicoptere.net
	 */
	public class PoissonDisk
	{
		static private var cellSize:Number;
		
		static private var min_dist_square:Number;
		
		static private var grid:Vector.<Vector.<Point>>;
		static private var processList:Vector.<Point>;
		static private var samplePoints:Vector.<Point>;
		static private var width:int;
		static private var height:int;
		
		
		static private var totalCell:int;
		static private var num_col:int;
		static private var num_row:int;
		static private var maxAttempts:int = 50;
		
		static public var bd:BitmapData;
		static private var buffer:BitmapData;
		static private var bufferSize:Number;
		
		public function PoissonDisk() 
		{
			
		}
		static public function generate_poisson( rect:Rectangle, min_dist:Number = 10, new_points_count:int = 50 ):Vector.<Point>
		{
			
			cellSize = min_dist / Math.SQRT2;
			
			bd = new BitmapData( rect.width, rect.height, true, 0 );
			bufferSize = 5 * cellSize;
			buffer = new BitmapData( bufferSize, bufferSize, true, 0 );
			
			min_dist_square = bufferSize * .5;
			
			var p:Point = new Point( Math.random() * rect.width, Math.random() * rect.height );
			var np:Point;
			
			samplePoints = Vector.<Point>( [ p ] );
			
			var color:uint = 0xFFFFFFFF;
			bd.setPixel32( p.x, p.y, color );
			
			
			while ( samplePoints.length < new_points_count )
			{
				
				//np = generateRandomPointAround( p, min_dist );
				np = new Point( Math.random() * rect.width, Math.random() * rect.height );
				
				search:if ( rect.containsPoint( np ) )
				{
					if ( !isAround( p, np ) )
					{
						
						bd.setPixel32( np.x, np.y, color );
						samplePoints.push( np );
						break search;
						
					}
				}
			}
			
			return samplePoints;
		}
		
		
		static private function isAround( p:Point, np:Point ):Boolean
		{
			
			var rect:Rectangle = new Rectangle( p.x - bufferSize * .5, p.y - bufferSize * .5, bufferSize, bufferSize );
			
			buffer.fillRect( buffer.rect, 0 );
			
			buffer.copyPixels( bd, rect, new Point( rect.x, rect.y ), null, null, true );
			
			buffer.setPixel32( p.x, p.y, 0 );
			
			//bd.fillRect( rect, 0xFFFF0000 );
			
			
			if ( buffer.threshold( buffer, buffer.rect, new Point(), '!=', 0xFFFFFFFF, 0 ) == 0 )
			{
				trace( 'vide' );
				return false;
			}
			
			var total:int = buffer.width * buffer.height;
			
			var dx:Number, dy:Number;
			var x:int, y:int;
			
			while ( total-- )
			{
				x = total % buffer.width;
				y = int( total / buffer.height );
				if ( buffer.getPixel32( x, y ) != 0 )
				{
					
					dx = p.x - x;
					dy = p.y - y;
					if ( ( dx * dx + dy * dy ) < min_dist_square ) return true;
					
				}
			}
			
			return false;
		}
		
		static private function generateRandomPointAround( point:Point, mindist:Number ):Point
		{
			
			//random radius between mindist and 2 * mindist
			var radius:Number = mindist + ( mindist * Math.random() );
			
			//random angle
			var angle:Number = ( 2 * Math.PI ) * Math.random();
			
			//the new point is generated around the point (x, y)
			return new Point( 	point.x + radius * Math.cos(angle),
								point.y + radius * Math.sin(angle) 	);
		
		}
		
	}

}
	